package com.example.demo.user.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.common.ErrorCode;
import com.example.demo.common.PageResult;
import com.example.demo.exception.ThrowUtils;
import com.example.demo.user.dto.UserCreateRequest;
import com.example.demo.user.dto.UserQueryRequest;
import com.example.demo.user.dto.UserResponse;
import com.example.demo.user.dto.UserUpdateRequest;
import com.example.demo.user.entity.User;
import com.example.demo.user.mapper.UserMapper;
import com.example.demo.user.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
@ConditionalOnProperty(prefix = "feature.database", name = "enabled", havingValue = "true", matchIfMissing = false)
public class UserServiceImpl implements UserService {

    private final UserMapper userMapper;

    @Override
    @Transactional
    public UserResponse register(UserCreateRequest request) {
        ThrowUtils.throwIf(request == null, ErrorCode.PARAMS_ERROR);
        String username = StrUtil.trim(request.getUsername());
        Long count = userMapper.selectCount(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
        ThrowUtils.throwIf(count > 0, ErrorCode.PARAMS_ERROR, "用户名已存在");

        User user = new User();
        user.setUsername(username);
        user.setNickname(request.getNickname());
        user.setPassword(encryptPassword(request.getPassword()));
        user.setRole("USER");
        user.setZipQuota(0);
        user.setZipUsed(0);
        user.setCreatedAt(LocalDateTime.now());
        user.setUpdatedAt(LocalDateTime.now());
        userMapper.insert(user);
        log.info("新用户注册成功: {}", user.getUsername());
        return toResponse(user);
    }

    @Override
    public PageResult<UserResponse> listUsers(UserQueryRequest request) {
        UserQueryRequest effective = request != null ? request : new UserQueryRequest();
        long current = Math.max(1, effective.getCurrent());
        long size = Math.max(1, effective.getPageSize());
        Page<User> page = new Page<>(current, size);

        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotBlank(effective.getKeyword())) {
            String keyword = StrUtil.trim(effective.getKeyword());
            queryWrapper.and(w -> w.like(User::getUsername, keyword).or().like(User::getNickname, keyword));
        }

        Page<User> result = userMapper.selectPage(page, queryWrapper);
        List<UserResponse> records = result.getRecords().stream()
                .map(this::toResponse)
                .collect(Collectors.toList());
        return PageResult.<UserResponse>builder()
                .records(records)
                .total(result.getTotal())
                .current(result.getCurrent())
                .pageSize(result.getSize())
                .build();
    }

    @Override
    public UserResponse getUser(Long id) {
        User user = loadUserOrThrow(id);
        return toResponse(user);
    }

    @Override
    @Transactional
    public UserResponse updateUser(Long id, UserUpdateRequest request) {
        ThrowUtils.throwIf(request == null, ErrorCode.PARAMS_ERROR);
        User user = loadUserOrThrow(id);

        if (StrUtil.isNotBlank(request.getNickname())) {
            user.setNickname(request.getNickname());
        }
        if (StrUtil.isNotBlank(request.getPassword())) {
            user.setPassword(encryptPassword(request.getPassword()));
        }
        user.setUpdatedAt(LocalDateTime.now());
        userMapper.updateById(user);
        return toResponse(user);
    }

    @Override
    @Transactional
    public void deleteUser(Long id) {
        loadUserOrThrow(id);
        userMapper.deleteById(id);
    }

    @Override
    @Transactional
    public UserResponse updateZipQuota(Long id, int quota, Integer used) {
        ThrowUtils.throwIf(quota < 0, ErrorCode.PARAMS_ERROR, "配额不能为负数");
        User user = loadUserOrThrow(id);
        user.setZipQuota(quota);
        if (used != null) {
            ThrowUtils.throwIf(used < 0, ErrorCode.PARAMS_ERROR, "已使用次数不能为负数");
            ThrowUtils.throwIf(quota > 0 && used > quota, ErrorCode.PARAMS_ERROR, "已使用次数不能超过配额");
            user.setZipUsed(used);
        }
        user.setUpdatedAt(LocalDateTime.now());
        userMapper.updateById(user);
        return toResponse(user);
    }

    @Override
    public void validateZipQuota(Long userId) {
        User user = loadUserOrThrow(userId);
        if (isAdmin(user)) {
            return;
        }
        int quota = user.getZipQuota() == null ? 0 : user.getZipQuota();
        int used = user.getZipUsed() == null ? 0 : user.getZipUsed();
        ThrowUtils.throwIf(quota <= 0, ErrorCode.FORBIDDEN_ERROR, "未被授权生成 ZIP");
        ThrowUtils.throwIf(used >= quota, ErrorCode.QUOTA_EXCEEDED, "ZIP 配额已用尽");
    }

    @Override
    @Transactional
    public void consumeZipQuota(Long userId) {
        validateZipQuota(userId);
        User user = loadUserOrThrow(userId);
        if (isAdmin(user)) {
            return;
        }
        int used = user.getZipUsed() == null ? 0 : user.getZipUsed();
        user.setZipUsed(used + 1);
        user.setUpdatedAt(LocalDateTime.now());
        userMapper.updateById(user);
    }

    @Override
    public User findByUsername(String username) {
        if (StrUtil.isBlank(username)) {
            return null;
        }
        return userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, StrUtil.trim(username)));
    }

    private User loadUserOrThrow(Long userId) {
        User user = userMapper.selectById(userId);
        ThrowUtils.throwIf(user == null, ErrorCode.NOT_FOUND_ERROR, "用户不存在");
        return user;
    }

    private boolean isAdmin(User user) {
        return user != null && "ADMIN".equalsIgnoreCase(user.getRole());
    }

    private String encryptPassword(String rawPassword) {
        return BCrypt.hashpw(rawPassword);
    }

    private UserResponse toResponse(User user) {
        return UserResponse.builder()
                .id(user.getId())
                .username(user.getUsername())
                .nickname(user.getNickname())
                .role(user.getRole())
                .zipQuota(user.getZipQuota() == null ? 0 : user.getZipQuota())
                .zipUsed(user.getZipUsed() == null ? 0 : user.getZipUsed())
                .createdAt(user.getCreatedAt())
                .updatedAt(user.getUpdatedAt())
                .build();
    }
}
